package cn.melonlib.cores.aop.comp.result;

import cn.melonlib.cores.aop.anno.result.TransToView;
import cn.melonlib.cores.aop.anno.result.TransToViewMethod;
import cn.melonlib.cores.aop.comp.TransToViewExecutor;
import cn.melonlib.cores.aop.enums.TransViewMode;
import cn.melonlib.cores.model.anno.WorkerQuery;
import cn.melonlib.cores.model.anno.WorkerService;
import cn.melonlib.cores.model.anno.WorkerStore;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.support.ApplicationObjectSupport;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Component
public class TransToViewInterceptor extends ApplicationObjectSupport implements MethodInterceptor {

    @Nullable
    @Override
    public Object invoke(@NotNull MethodInvocation invocation) throws Throwable {
        TransToViewMethod transViewMethod=AnnotationUtils.findAnnotation(invocation.getMethod(),TransToViewMethod.class);
        TransToView transToView=AnnotationUtils.findAnnotation(AopUtils.getTargetClass(invocation.getThis()),TransToView.class);
        if(validMethod(AopUtils.getTargetClass(invocation.getThis()),invocation.getMethod())) {
            return this.getApplicationContext().getBean(TransToViewExecutor.class, Objects.nonNull(transViewMethod) ? transViewMethod.value() : transToView.value())
                    .trans(invocation.proceed(), invocation.getThis(),invocation.getMethod());
        }else{
            return invocation.proceed();
        }
    }

    public static boolean validMethod(Class<?> targetClass, Method method){
        TransToView transToView=AnnotationUtils.findAnnotation(targetClass, TransToView.class);
        if(transToView==null){
            return false;
        }
        TransToViewMethod transViewMethod=AnnotationUtils.findAnnotation(method,TransToViewMethod.class);
        if(transViewMethod!=null){
            return true;
        }
        String methodName=method.getName();
//        if(Arrays.stream(operatorRecordService.excludes()).anyMatch(regex-> Pattern.compile(regex).matcher(methodName).matches())){
//            return false;
//        };
        if(Arrays.stream(transToView.includes()).anyMatch(regex-> Pattern.compile(regex).matcher(methodName).matches())){
            return true;
        }
        TransViewMode mode=transToView.mode();
        switch (mode){
            case NONE:return false;
            case ALL:return true;
            case QUERY:return AnnotationUtils.findAnnotation(targetClass, WorkerService.class)!=null
                    &&AnnotationUtils.findAnnotation(method, WorkerQuery.class)!=null;
            case STORE:return AnnotationUtils.findAnnotation(targetClass, WorkerService.class)!=null
                    &&AnnotationUtils.findAnnotation(method, WorkerStore.class)!=null;
            case WORKER:return AnnotationUtils.findAnnotation(targetClass, WorkerService.class)!=null&&
                    (AnnotationUtils.findAnnotation(method, WorkerQuery.class)!=null
                            ||AnnotationUtils.findAnnotation(method, WorkerStore.class)!=null);
            default:return false;
        }
    }
}
